import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk
import sqlite3
import os
from datetime import datetime
import glob
import shutil
import webbrowser

class ComicManager:
    def __init__(self, root):
        self.root = root
        self.root.title("漫画管理工具")
        self.root.geometry("1200x800")
        self.root.configure(bg="#2c3e50")
        
        # 初始化数据库
        self.init_db()
        
        # 创建界面
        self.create_ui()
        
        # 加载漫画数据
        self.current_page = 1
        self.per_page = 20
        self.selected_comics = set()
        self.comic_checkboxes = {}  # 初始化复选框字典
        self.cover_images = {}  # 存储封面图像引用
        
        # 延迟加载漫画，确保窗口已完全显示
        self.root.after(100, self.load_comics)
        
        # 绑定窗口大小变化事件
        self.root.bind("<Configure>", self.on_window_resize)

    def init_db(self):
        self.conn = sqlite3.connect('comic_manager.db')
        self.cursor = self.conn.cursor()
        
        # 创建漫画表
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS comics (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                folder_path TEXT NOT NULL,
                cover_path TEXT,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        # 创建标签表
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS tags (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL UNIQUE
            )
        ''')
        
        # 创建漫画标签关联表
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS comic_tags (
                comic_id INTEGER,
                tag_id INTEGER,
                tag_name TEXT,
                PRIMARY KEY (comic_id, tag_id),
                FOREIGN KEY (comic_id) REFERENCES comics(id),
                FOREIGN KEY (tag_id) REFERENCES tags(id)
            )
        ''')
        
        self.conn.commit()

    def create_ui(self):
        # 主框架
        main_container = tk.Frame(self.root, bg="#2c3e50")
        main_container.pack(fill="both", expand=True)
        
        # 顶部栏
        top_frame = tk.Frame(main_container, bg="#34495e", height=40)
        top_frame.pack(fill="x", padx=10, pady=10)
        
        import_btn = tk.Button(top_frame, text="导入漫画", command=self.import_comics, 
                             bg="#3498db", fg="white", font=("Arial", 10, "bold"))
        import_btn.pack(side="left", padx=5, pady=5)
        
        # 工具栏
        toolbar = tk.Frame(main_container, bg="#34495e", height=40)
        toolbar.pack(fill="x", padx=10, pady=(0, 10))
        
        search_frame = tk.Frame(toolbar, bg="#34495e")
        search_frame.pack(side="left", padx=5)
        
        search_options = ["按名称", "按标签"]
        self.search_var = tk.StringVar(value=search_options[0])
        search_dropdown = ttk.Combobox(search_frame, textvariable=self.search_var, 
                                      values=search_options, width=8, state="readonly")
        search_dropdown.pack(side="left", padx=(0, 5))
        search_dropdown.bind("<<ComboboxSelected>>", self.on_search_type_changed)
        
        # 搜索输入框 - 初始为普通文本框
        self.search_entry = tk.Entry(search_frame, width=30)
        self.search_entry.pack(side="left", padx=(0, 5))
        
        # 标签选择下拉框 - 初始隐藏
        self.tag_search_var = tk.StringVar()
        self.tag_search_combo = ttk.Combobox(search_frame, textvariable=self.tag_search_var, 
                                           width=28, state="readonly")
        self.tag_search_combo.pack(side="left", padx=(0, 5))
        self.tag_search_combo.pack_forget()  # 初始隐藏
        
        search_btn = tk.Button(search_frame, text="查询", command=self.search_comics,
                             bg="#2ecc71", fg="white")
        search_btn.pack(side="left")
        
        # 批量操作按钮
        batch_frame = tk.Frame(toolbar, bg="#34495e")
        batch_frame.pack(side="right", padx=5)
        
        self.select_all_var = tk.BooleanVar()
        select_all_btn = tk.Checkbutton(batch_frame, text="全选", variable=self.select_all_var,
                                       command=self.toggle_select_all, bg="#34495e", fg="white",
                                       selectcolor="#34495e")
        select_all_btn.pack(side="left", padx=5)
        
        remove_btn = tk.Button(batch_frame, text="批量移除", command=self.batch_remove,
                             bg="#e74c3c", fg="white")
        remove_btn.pack(side="left", padx=5)
        
        tag_btn = tk.Button(batch_frame, text="批量添加标签", command=self.batch_add_tags,
                          bg="#f39c12", fg="white")
        tag_btn.pack(side="left", padx=5)
        
        # 主程序区容器
        content_frame = tk.Frame(main_container, bg="#2c3e50")
        content_frame.pack(fill="both", expand=True, padx=10, pady=(0, 10))
        
        # 漫画展示区 - 使用Canvas和Frame实现滚动
        canvas_frame = tk.Frame(content_frame, bg="#2c3e50")
        canvas_frame.pack(fill="both", expand=True)
        
        # 创建一个容器框架来放置Canvas和滚动条，确保滚动条不会遮挡内容
        canvas_container = tk.Frame(canvas_frame, bg="#2c3e50")
        canvas_container.pack(fill="both", expand=True)
        
        self.comic_canvas = tk.Canvas(canvas_container, bg="#2c3e50", highlightthickness=0)
        self.scrollbar = ttk.Scrollbar(canvas_container, orient="vertical", command=self.comic_canvas.yview)
        self.scrollable_frame = tk.Frame(self.comic_canvas, bg="#2c3e50")
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.comic_canvas.configure(
                scrollregion=self.comic_canvas.bbox("all")
            )
        )
        
        self.comic_canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.comic_canvas.configure(yscrollcommand=self.scrollbar.set)
        
        self.comic_canvas.pack(side="left", fill="both", expand=True)
        self.scrollbar.pack(side="right", fill="y")
        
        # 分页控件
        page_frame = tk.Frame(main_container, bg="#2c3e50", height=40)
        page_frame.pack(fill="x", padx=10, pady=(0, 10))
        
        # 添加首页按钮
        self.first_btn = tk.Button(page_frame, text="首页", command=self.first_page,
                                bg="#7f8c8d", fg="white", state="disabled")
        self.first_btn.pack(side="left", padx=5)
        
        self.prev_btn = tk.Button(page_frame, text="上一页", command=self.prev_page,
                                bg="#7f8c8d", fg="white", state="disabled")
        self.prev_btn.pack(side="left", padx=5)
        
        self.page_label = tk.Label(page_frame, text="第1页", bg="#2c3e50", fg="white")
        self.page_label.pack(side="left", padx=5)
        
        self.next_btn = tk.Button(page_frame, text="下一页", command=self.next_page,
                                bg="#7f8c8d", fg="white")
        self.next_btn.pack(side="left", padx=5)
        
        # 添加尾页按钮
        self.last_btn = tk.Button(page_frame, text="尾页", command=self.last_page,
                                bg="#7f8c8d", fg="white")
        self.last_btn.pack(side="left", padx=5)
        
        # 介绍栏
        info_frame = tk.LabelFrame(main_container, text="漫画详情", bg="#34495e", fg="white", padx=10, pady=10)
        info_frame.pack(fill="x", padx=10, pady=(0, 10))
        
        self.comic_name = tk.Label(info_frame, text="未选中漫画", bg="#34495e", fg="#3498db",
                                 font=("Arial", 12, "bold"))
        self.comic_name.pack(anchor="w", pady=(0, 5))
        
        self.comic_tags = tk.Label(info_frame, text="标签: 无", bg="#34495e", fg="#ecf0f1",
                                  font=("Arial", 10))
        self.comic_tags.pack(anchor="w")
        
        # 路径标签改为可点击
        self.comic_path = tk.Label(info_frame, text="路径: 无", bg="#34495e", fg="#bdc3c7",
                                 font=("Arial", 9), cursor="hand2")
        self.comic_path.pack(anchor="w")
        self.comic_path.bind("<Button-1>", self.open_folder)
        
        # 右键菜单
        self.context_menu = tk.Menu(self.root, tearoff=0)
        self.context_menu.add_command(label="阅读漫画", command=self.read_comic)
        self.context_menu.add_command(label="设置标签", command=self.set_tags)
        self.context_menu.add_command(label="移除漫画", command=self.remove_comic)
        self.context_menu.add_command(label="修改封面", command=self.change_cover)  # 新增修改封面功能
        
        # 绑定鼠标滚轮事件
        self.comic_canvas.bind_all("<MouseWheel>", self._on_mousewheel)

    def on_search_type_changed(self, event):
        """当搜索类型改变时切换输入控件"""
        search_type = self.search_var.get()
        
        if search_type == "按标签":
            # 隐藏普通搜索框，显示标签选择框
            self.search_entry.pack_forget()
            self.tag_search_combo.pack(side="left", padx=(0, 5))
            
            # 加载所有标签到下拉框
            self.cursor.execute("SELECT name FROM tags ORDER BY name")
            all_tags = [row[0] for row in self.cursor.fetchall()]
            self.tag_search_combo['values'] = all_tags
        else:
            # 隐藏标签选择框，显示普通搜索框
            self.tag_search_combo.pack_forget()
            self.search_entry.pack(side="left", padx=(0, 5))

    def on_scrollable_frame_configure(self, event):
        """当可滚动框架大小改变时更新滚动区域"""
        self.comic_canvas.configure(scrollregion=self.comic_canvas.bbox("all"))

    def on_canvas_configure(self, event):
        """当Canvas大小改变时调整内部框架的宽度"""
        # 设置可滚动框架的宽度与Canvas相同
        canvas_width = event.width
        self.comic_canvas.itemconfig(self.canvas_frame_id, width=canvas_width)
        
        # 重新加载漫画以调整图片大小
        if hasattr(self, 'current_search_query'):
            self.load_comics(self.current_search_query, self.current_search_type)

    def on_window_resize(self, event):
        # 当窗口大小改变时，重新加载漫画以调整图片大小
        if event.widget == self.root:
            self.load_comics(self.current_search_query, self.current_search_type)

    def _on_mousewheel(self, event):
        self.comic_canvas.yview_scroll(int(-1*(event.delta/120)), "units")

    def import_comics(self):
        folder_path = filedialog.askdirectory(title="选择漫画库文件夹")
        if not folder_path:
            return
        # 获取所有子文件夹
        for comic_folder in os.listdir(folder_path):
            comic_path = os.path.join(folder_path, comic_folder)
            if os.path.isdir(comic_path):
                # 检查是否已存在
                self.cursor.execute("SELECT id FROM comics WHERE folder_path=?", (comic_path,))
                if self.cursor.fetchone():
                    continue
                
                # 查找封面图
                cover_path = None
                poster_path = os.path.join(comic_path, "poster.*")
                poster_files = glob.glob(poster_path)
                if poster_files:
                    cover_path = poster_files[0]
                else:
                    # 使用文件夹中第一张图片为封面,如果当前文件夹下没有,就向子文件夹下查找
                    for file in os.listdir(comic_path):
                        file_path = os.path.join(comic_path, file)
                        if os.path.isfile(file_path) and self.is_image(file_path):
                            cover_path = file_path
                            break
                        else:
                            # 如果当前文件夹没有图片文件，向子文件夹查找
                            for root, dirs, files in os.walk(comic_path):
                                for file in files:
                                    file_path = os.path.join(root, file)
                                    if self.is_image(file_path):
                                        cover_path = file_path
                                        break
                                if cover_path:
                                    break
                    if not cover_path:
                        cover_path = "default_cover.png"
                    
                
                # 插入数据库
                self.cursor.execute(
                    "INSERT INTO comics (name, folder_path, cover_path, created_at) VALUES (?, ?, ?, ?)",
                    (comic_folder, comic_path, cover_path, datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
                )
        
        self.conn.commit()
        self.load_comics()
        messagebox.showinfo("导入成功", f"成功导入漫画库！")

    def is_image(self, file_path):
        try:
            with Image.open(file_path) as img:
                img.verify()  # 验证文件是否为有效图片
            return True
        except (IOError, SyntaxError, ValueError):
            return False

    def load_comics(self, search_query=None, search_type="按名称"):
        # 清空当前显示
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        
        # 存储当前搜索条件
        self.current_search_query = search_query
        self.current_search_type = search_type
        
        # 计算分页
        offset = (self.current_page - 1) * self.per_page
        
        # 查询数据库
        query = "SELECT id, name, folder_path, cover_path FROM comics"
        params = []
        
        if search_query:
            if search_type == "按名称":
                query += " WHERE name LIKE ?"
                params.append(f"%{search_query}%")
            elif search_type == "按标签":
                # 处理多标签查询
                tags = search_query.split(',')
                if tags:
                    query += " WHERE id IN ("
                    query += "SELECT comic_id FROM comic_tags WHERE tag_name IN ({})".format(
                        ','.join(['?'] * len(tags)))
                    query += " GROUP BY comic_id HAVING COUNT(DISTINCT tag_name) = ?)"
                    params.extend(tags)
                    params.append(len(tags))
        
        query += " LIMIT ? OFFSET ?"
        params.extend([self.per_page, offset])
        
        self.cursor.execute(query, params)
        comics = self.cursor.fetchall()
        
        # 计算封面图片大小
        canvas_width = self.comic_canvas.winfo_width()
        if canvas_width < 100:  # 初始加载时宽度可能为0
            canvas_width = self.root.winfo_width() - 50  # 使用窗口宽度减去边距
        
        # 每行5个漫画，计算每个漫画项的宽度 保持宽高比 2:3
        item_width = max(120, (canvas_width - 100) // 5)
        item_height = int(item_width * 1.5)
        
        # 显示漫画
        row_frame = None
        for i, comic in enumerate(comics):
            comic_id, name, folder_path, cover_path = comic
            
            if i % 5 == 0:
                row_frame = tk.Frame(self.scrollable_frame, bg="#2c3e50")
                row_frame.pack(fill="x", pady=5)
            
            # 漫画项容器
            item_frame = tk.Frame(row_frame, bg="#34495e", padx=5, pady=5)
            item_frame.pack(side="left", padx=10)
            
            # 复选框
            var = tk.BooleanVar()
            chk = tk.Checkbutton(item_frame, variable=var, bg="#34495e", 
                               command=lambda cid=comic_id, v=var: self.toggle_comic(cid, v))
            chk.pack(anchor="nw")
            
            # 封面 - 修改部分开始
            try:
                # 检查封面路径是否存在
                if not os.path.exists(cover_path):
                    # 如果封面不存在，尝试重新查找封面
                    new_cover_path = self.find_cover(folder_path)
                    if new_cover_path != cover_path:
                        # 更新数据库中的封面路径
                        self.cursor.execute("UPDATE comics SET cover_path=? WHERE id=?", 
                                          (new_cover_path, comic_id))
                        self.conn.commit()
                        cover_path = new_cover_path
                
                # 加载封面图片
                img = Image.open(cover_path)
                
                # 保持2:3比例，按最大边缩放
                target_ratio = 2/3
                img_ratio = img.width / img.height
                
                if img_ratio > target_ratio:
                    # 图片太宽，按高度缩放
                    new_height = item_height
                    new_width = int(new_height * img_ratio)
                    img = img.resize((new_width, new_height), Image.LANCZOS)
                    # 裁剪宽度
                    left = (new_width - item_width) // 2
                    img = img.crop((left, 0, left + item_width, new_height))
                else:
                    # 图片太高，按宽度缩放
                    new_width = item_width
                    new_height = int(new_width / img_ratio)
                    img = img.resize((new_width, new_height), Image.LANCZOS)
                    # 裁剪高度
                    top = (new_height - item_height) // 2
                    img = img.crop((0, top, new_width, top + item_height))
                
                photo = ImageTk.PhotoImage(img)
                
                # 存储图像引用
                self.cover_images[comic_id] = photo
                
                cover_label = tk.Label(item_frame, image=photo, bg="#34495e", 
                                     cursor="hand2", relief="raised", bd=2)
                cover_label.image = photo
                cover_label.pack()
                
                # 绑定事件
                cover_label.bind("<Button-1>", lambda e, cid=comic_id: self.select_comic(cid))
                cover_label.bind("<Button-3>", lambda e, cid=comic_id: self.show_context_menu(e, cid))
            except Exception as e:
                print(f"加载封面错误: {e}")
                # 使用默认封面
                default_label = tk.Label(item_frame, text="封面缺失", width=15, height=8, 
                                       bg="#7f8c8d", fg="white", relief="raised", bd=2)
                default_label.pack()
                default_label.bind("<Button-1>", lambda e, cid=comic_id: self.select_comic(cid))
                default_label.bind("<Button-3>", lambda e, cid=comic_id: self.show_context_menu(e, cid))
            # 封面 - 修改部分结束
            
            # 漫画名称
            name_label = tk.Label(item_frame, text=name, bg="#34495e", fg="white", 
                                cursor="hand2", wraplength=item_width-10)
            name_label.pack()
            name_label.bind("<Button-1>", lambda e, cid=comic_id: self.select_comic(cid))
            name_label.bind("<Button-3>", lambda e, cid=comic_id: self.show_context_menu(e, cid))
            
            # 记录复选框状态
            self.comic_checkboxes[comic_id] = var
            
        # 更新分页按钮状态
        self.update_pagination()
        
        # 重置选中状态
        self.selected_comics.clear()
        self.select_all_var.set(False)

    def find_cover(self, folder_path):
        """查找文件夹中的封面图片"""
        # 查找poster.*文件
        poster_path = os.path.join(folder_path, "poster.*")
        poster_files = glob.glob(poster_path)
        if poster_files:
            return poster_files[0]
        
        # 使用文件夹中第一张图片为封面
        image_exts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
        for file in os.listdir(folder_path):
            file_path = os.path.join(folder_path, file)
            if os.path.isfile(file_path) and os.path.splitext(file)[1].lower() in image_exts:
                return file_path
        
        # 如果当前文件夹没有图片文件，向子文件夹查找
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                file_path = os.path.join(root, file)
                if os.path.splitext(file)[1].lower() in image_exts:
                    return file_path
        
        # 如果找不到任何图片，返回默认封面路径
        return "default_cover.png"

    def update_pagination(self):
        # 查询总数
        if self.current_search_query and self.current_search_type == "按标签":
            tags = self.current_search_query.split(',')
            self.cursor.execute("""
                SELECT COUNT(DISTINCT c.id) 
                FROM comics c
                JOIN comic_tags ct ON c.id = ct.comic_id
                WHERE ct.tag_name IN ({})
                GROUP BY c.id
                HAVING COUNT(DISTINCT ct.tag_name) = ?
            """.format(','.join(['?'] * len(tags))), tags + [len(tags)])
        elif self.current_search_query:
            self.cursor.execute("SELECT COUNT(*) FROM comics WHERE name LIKE ?", 
                              (f"%{self.current_search_query}%",))
        else:
            self.cursor.execute("SELECT COUNT(*) FROM comics")
        
        total = self.cursor.fetchone()[0]
        total_pages = max(1, (total + self.per_page - 1) // self.per_page)
        
        # 更新标签
        self.page_label.config(text=f"第{self.current_page}页/共{total_pages}页")
        
        # 更新按钮状态
        self.prev_btn.config(state="normal" if self.current_page > 1 else "disabled")
        self.next_btn.config(state="normal" if self.current_page < total_pages else "disabled")
        self.first_btn.config(state="normal" if self.current_page > 1 else "disabled")
        self.last_btn.config(state="normal" if self.current_page < total_pages else "disabled")

    def first_page(self):
        if self.current_page > 1:
            self.current_page = 1
            self.load_comics(self.current_search_query, self.current_search_type)

    def prev_page(self):
        if self.current_page > 1:
            self.current_page -= 1
            self.load_comics(self.current_search_query, self.current_search_type)

    def next_page(self):
        # 查询总数
        if self.current_search_query and self.current_search_type == "按标签":
            tags = self.current_search_query.split(',')
            self.cursor.execute("""
                SELECT COUNT(DISTINCT c.id) 
                FROM comics c
                JOIN comic_tags ct ON c.id = ct.comic_id
                WHERE ct.tag_name IN ({})
                GROUP BY c.id
                HAVING COUNT(DISTINCT ct.tag_name) = ?
            """.format(','.join(['?'] * len(tags))), tags + [len(tags)])
        elif self.current_search_query:
            self.cursor.execute("SELECT COUNT(*) FROM comics WHERE name LIKE ?", 
                              (f"%{self.current_search_query}%",))
        else:
            self.cursor.execute("SELECT COUNT(*) FROM comics")
        
        total = self.cursor.fetchone()[0]
        total_pages = max(1, (total + self.per_page - 1) // self.per_page)
        
        if self.current_page < total_pages:
            self.current_page += 1
            self.load_comics(self.current_search_query, self.current_search_type)

    def last_page(self):
        # 查询总数
        if self.current_search_query and self.current_search_type == "按标签":
            tags = self.current_search_query.split(',')
            self.cursor.execute("""
                SELECT COUNT(DISTINCT c.id) 
                FROM comics c
                JOIN comic_tags ct ON c.id = ct.comic_id
                WHERE ct.tag_name IN ({})
                GROUP BY c.id
                HAVING COUNT(DISTINCT ct.tag_name) = ?
            """.format(','.join(['?'] * len(tags))), tags + [len(tags)])
        elif self.current_search_query:
            self.cursor.execute("SELECT COUNT(*) FROM comics WHERE name LIKE ?", 
                              (f"%{self.current_search_query}%",))
        else:
            self.cursor.execute("SELECT COUNT(*) FROM comics")
        
        total = self.cursor.fetchone()[0]
        total_pages = max(1, (total + self.per_page - 1) // self.per_page)
        
        if self.current_page < total_pages:
            self.current_page = total_pages
            self.load_comics(self.current_search_query, self.current_search_type)

    def search_comics(self):
        search_type = self.search_var.get()
        
        if search_type == "按标签":
            query = self.tag_search_var.get()
        else:
            query = self.search_entry.get()
            
        self.current_page = 1
        self.load_comics(query, search_type)

    def toggle_comic(self, comic_id, var):
        if var.get():
            self.selected_comics.add(comic_id)
        else:
            self.selected_comics.discard(comic_id)

    def toggle_select_all(self):
        select_all = self.select_all_var.get()
        for comic_id, var in self.comic_checkboxes.items():
            var.set(select_all)
            if select_all:
                self.selected_comics.add(comic_id)
            else:
                self.selected_comics.discard(comic_id)

    def select_comic(self, comic_id):
        # 清除所有复选框
        for cid, var in self.comic_checkboxes.items():
            var.set(cid == comic_id)
        
        # 更新选中集合
        self.selected_comics = {comic_id} if comic_id in self.comic_checkboxes else set()
        
        # 更新详情
        self.cursor.execute("SELECT name, folder_path FROM comics WHERE id=?", (comic_id,))
        comic = self.cursor.fetchone()
        if comic:
            name, folder_path = comic
            self.comic_name.config(text=name)
            self.comic_path.config(text=f"路径: {folder_path}")
            
            # 获取标签
            self.cursor.execute("SELECT tag_name FROM comic_tags WHERE comic_id=?", (comic_id,))
            tags = [row[0] for row in self.cursor.fetchall()]
            tag_text = "标签: " + (", ".join(tags) if tags else "无")
            self.comic_tags.config(text=tag_text)

    def show_context_menu(self, event, comic_id):
        self.select_comic(comic_id)
        self.context_menu.post(event.x_root, event.y_root)

    def read_comic(self):
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择一个漫画！")
            return
        
        comic_id = next(iter(self.selected_comics))
        self.cursor.execute("SELECT folder_path FROM comics WHERE id=?", (comic_id,))
        folder_path = self.cursor.fetchone()[0]
        
        # 创建阅读窗口
        reader = tk.Toplevel(self.root)
        reader.title("漫画阅读器")
        reader.geometry("1000x700")
        reader.minsize(800, 600)
        
        # 获取图片列表
        self.all_image_files = []
        image_exts = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
        # 使用os.walk递归遍历所有文件
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                # 获取文件扩展名并转换为小写
                file_ext = os.path.splitext(file)[1].lower()
                
                # 检查扩展名是否在支持的列表中
                if file_ext in image_exts:
                    self.all_image_files.append(os.path.join(root, file))

        if not self.all_image_files:
            tk.Label(reader, text="未找到图片文件", padx=20, pady=20).pack()
            return
        
        self.all_image_files.sort()
        self.current_chapter_image_files = self.all_image_files  # 初始化为所有图片
        self.current_index = 0
        
        # 主容器 - 使用Grid布局管理器，确保各部分不会互相遮挡
        main_frame = tk.Frame(reader, bg="#2c3e50")
        main_frame.pack(fill="both", expand=True, padx=10, pady=10)
        
        # 章节列表 - 放在顶部
        chapters = []
        for root, dirs, files in os.walk(folder_path):
            if root != folder_path:
                chapters.append(root)
        
        chapter_frame = None
        if chapters:
            chapter_frame = tk.Frame(main_frame, bg="#34495e")
            chapter_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=(0, 10))
            
            tk.Label(chapter_frame, text="章节列表:", bg="#34495e", fg="white").pack(anchor="w")
            
            # 创建水平滚动容器
            chapter_container = tk.Frame(chapter_frame, bg="#34495e")
            chapter_container.pack(fill="x", pady=5)
            
            # 添加水平滚动条
            h_scrollbar = ttk.Scrollbar(chapter_container, orient="horizontal")
            h_scrollbar.pack(side="bottom", fill="x")
            
            # 创建Canvas用于水平滚动
            chapter_canvas = tk.Canvas(chapter_container, bg="#34495e", height=30, 
                                     xscrollcommand=h_scrollbar.set, highlightthickness=0)
            chapter_canvas.pack(side="top", fill="x", expand=True)
            
            h_scrollbar.config(command=chapter_canvas.xview)
            
            # 创建按钮容器
            button_frame = tk.Frame(chapter_canvas, bg="#34495e")
            chapter_canvas.create_window((0, 0), window=button_frame, anchor="nw")
            
            for i, chapter in enumerate(chapters):
                chapter_name = os.path.basename(chapter)
                btn = tk.Button(button_frame, text=chapter_name, 
                               command=lambda c=chapter: self.load_chapter(c))
                btn.pack(side="left", padx=2)
            
            # 更新滚动区域
            def update_scroll_region(event):
                chapter_canvas.configure(scrollregion=chapter_canvas.bbox("all"))
            
            button_frame.bind("<Configure>", update_scroll_region)
        
        # 图片显示区域 - 放在中间
        img_frame = tk.Frame(main_frame, bg="#2c3e50")
        img_frame.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
        main_frame.rowconfigure(1, weight=1)  # 设置图片区域可扩展
        
        self.img_label = tk.Label(img_frame, bg="#2c3e50")
        self.img_label.pack(fill="both", expand=True)
        
        # 控制栏 - 放在底部
        ctrl_frame = tk.Frame(main_frame, bg="#34495e")
        ctrl_frame.grid(row=2, column=0, sticky="ew", padx=10, pady=10)
        
        prev_btn = tk.Button(ctrl_frame, text="上一页", 
                           command=lambda: self.change_image(-1))
        prev_btn.pack(side="left", padx=10)
        
        next_btn = tk.Button(ctrl_frame, text="下一页", 
                           command=lambda: self.change_image(1))
        next_btn.pack(side="left", padx=10)
        
        # 配置网格权重，确保图片区域可以扩展
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(1, weight=1)
        
        # 绑定窗口大小变化事件
        reader.bind("<Configure>", self.resize_reader_image)
        
        # 加载第一张图片
        self.load_image(self.current_chapter_image_files[self.current_index])
    
    def resize_reader_image(self, event):
        # 忽略小幅度变化
        if not hasattr(self, 'last_resize_time'):
            self.last_resize_time = 0
        
        current_time = datetime.now().timestamp()
        if current_time - self.last_resize_time > 0.2:  # 200ms防抖
            self.last_resize_time = current_time
            if hasattr(self, 'current_chapter_image_files') and self.current_chapter_image_files:
                self.load_image(self.current_chapter_image_files[self.current_index])

    def load_chapter(self, chapter_path):
        image_files = []
        image_exts = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
        # 使用os.walk递归遍历所有文件
        for root, dirs, files in os.walk(chapter_path):
            for file in files:
                # 获取文件扩展名并转换为小写
                file_ext = os.path.splitext(file)[1].lower()
                
                # 检查扩展名是否在支持的列表中
                if file_ext in image_exts:
                    image_files.append(os.path.join(root, file))
        
        if image_files:
            image_files.sort()
            self.current_chapter_image_files = image_files
            self.current_index = 0
            self.load_image(image_files[0])

    def change_image(self, direction):
        new_index = max(0, min(len(self.current_chapter_image_files) - 1, self.current_index + direction))
        if new_index != self.current_index:
            self.current_index = new_index
            self.load_image(self.current_chapter_image_files[self.current_index])

    def load_image(self, path):
        try:
            img = Image.open(path)
            
            # 获取当前窗口大小
            if self.img_label.winfo_width() > 10 and self.img_label.winfo_height() > 10:
                max_width = self.img_label.winfo_width() - 20
                max_height = self.img_label.winfo_height() - 20
            else:
                max_width = 800
                max_height = 600
            
            # 计算缩放比例
            width_ratio = max_width / img.width
            height_ratio = max_height / img.height
            scale_ratio = min(width_ratio, height_ratio)
            
            # 缩放图片
            new_width = int(img.width * scale_ratio)
            new_height = int(img.height * scale_ratio)
            img = img.resize((new_width, new_height), Image.LANCZOS)
            
            photo = ImageTk.PhotoImage(img)
            self.img_label.config(image=photo)
            self.img_label.image = photo
        except Exception as e:
            print(f"加载图片错误: {e}")

    def set_tags(self):
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择一个漫画！")
            return
        
        comic_id = next(iter(self.selected_comics))
        
        # 获取当前标签
        self.cursor.execute("SELECT tag_name FROM comic_tags WHERE comic_id=?", (comic_id,))
        current_tags = {row[0] for row in self.cursor.fetchall()}
        
        # 创建标签窗口
        tag_win = tk.Toplevel(self.root)
        tag_win.title("设置标签")
        tag_win.geometry("400x300")
        
        # 常用标签
        self.cursor.execute("SELECT name FROM tags ORDER BY id DESC LIMIT 10")
        common_tags = [row[0] for row in self.cursor.fetchall()]
        
        tag_frame = tk.Frame(tag_win, padx=10, pady=10)
        tag_frame.pack(fill="both", expand=True)
        
        tk.Label(tag_frame, text="添加标签:").pack(anchor="w", pady=(0, 5))
        
        tag_entry = tk.Entry(tag_frame, width=30)
        tag_entry.pack(fill="x", pady=(0, 10))
        tag_entry.focus()
        
        # 常用标签区域
        if common_tags:
            tk.Label(tag_frame, text="常用标签:").pack(anchor="w", pady=(0, 5))
            
            common_frame = tk.Frame(tag_frame)
            common_frame.pack(fill="x", pady=(0, 10))
            
            for tag in common_tags:
                btn = tk.Button(common_frame, text=tag, 
                              command=lambda t=tag: tag_entry.insert(tk.END, t + ","))
                btn.pack(side="left", padx=5)
        
        # 当前标签区域
        tk.Label(tag_frame, text="当前标签:").pack(anchor="w", pady=(0, 5))
        
        current_frame = tk.Frame(tag_frame)
        current_frame.pack(fill="x", pady=(0, 10))
        
        for tag in current_tags:
            tag_frame = tk.Frame(current_frame, relief="groove", bd=1, padx=5, pady=2)
            tag_frame.pack(side="left", padx=5)
            
            tk.Label(tag_frame, text=tag).pack(side="left")
            tk.Button(tag_frame, text="×", command=lambda t=tag: self.remove_tag(tag_win, comic_id, t), 
                    width=2).pack(side="left", padx=(5, 0))
        
        # 按钮区域
        btn_frame = tk.Frame(tag_frame)
        btn_frame.pack(fill="x", pady=10)
        
        tk.Button(btn_frame, text="保存", 
                 command=lambda: self.save_tags(tag_win, comic_id, tag_entry.get(), current_tags)).pack(side="right", padx=5)
        tk.Button(btn_frame, text="取消", command=tag_win.destroy).pack(side="right", padx=5)

    def remove_tag(self, window, comic_id, tag_name):
        # 从关联表中删除
        self.cursor.execute("DELETE FROM comic_tags WHERE comic_id=? AND tag_name=?", (comic_id, tag_name))
        self.conn.commit()
        
        # 关闭并重新打开窗口刷新
        window.destroy()
        self.set_tags()

    def save_tags(self, window, comic_id, new_tags, current_tags):
        new_tags = [tag.strip() for tag in new_tags.split(",") if tag.strip()]
        
        for tag in new_tags:
            # 如果标签已存在，跳过
            if tag in current_tags:
                continue
            
            # 检查标签是否在标签表中
            self.cursor.execute("SELECT id FROM tags WHERE name=?", (tag,))
            tag_row = self.cursor.fetchone()
            
            if not tag_row:
                # 插入新标签
                self.cursor.execute("INSERT INTO tags (name) VALUES (?)", (tag,))
                tag_id = self.cursor.lastrowid
            else:
                tag_id = tag_row[0]
            
            # 插入关联
            self.cursor.execute(
                "INSERT INTO comic_tags (comic_id, tag_id, tag_name) VALUES (?, ?, ?)",
                (comic_id, tag_id, tag)
            )
        
        self.conn.commit()
        window.destroy()
        
        # 更新详情显示
        self.select_comic(comic_id)

    def remove_comic(self):
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择一个漫画！")
            return
        
        comic_id = next(iter(self.selected_comics))
        
        # 确认删除
        if not messagebox.askyesno("确认删除", "确定要删除这个漫画吗？"):
            return
        
        # 删除关联标签
        self.cursor.execute("DELETE FROM comic_tags WHERE comic_id=?", (comic_id,))
        
        # 删除漫画
        self.cursor.execute("DELETE FROM comics WHERE id=?", (comic_id,))
        self.conn.commit()
        
        # 重新加载
        self.load_comics()
        
        # 清空详情
        self.comic_name.config(text="未选中漫画")
        self.comic_tags.config(text="标签: 无")
        self.comic_path.config(text="路径: 无")

    def batch_remove(self):
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择要删除的漫画！")
            return
        
        count = len(self.selected_comics)
        
        # 确认删除
        if not messagebox.askyesno("确认删除", f"确定要删除选中的{count}个漫画吗？"):
            return
        
        # 删除关联标签
        for comic_id in self.selected_comics:
            self.cursor.execute("DELETE FROM comic_tags WHERE comic_id=?", (comic_id,))
        
        # 删除漫画
        self.cursor.executemany("DELETE FROM comics WHERE id=?", [(cid,) for cid in self.selected_comics])
        self.conn.commit()
        
        # 重新加载
        self.load_comics()
        
        # 清空详情
        self.comic_name.config(text="未选中漫画")
        self.comic_tags.config(text="标签: 无")
        self.comic_path.config(text="路径: 无")

    def batch_add_tags(self):
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择要添加标签的漫画！")
            return
        
        # 创建标签窗口
        tag_win = tk.Toplevel(self.root)
        tag_win.title("批量添加标签")
        tag_win.geometry("400x200")
        
        tag_frame = tk.Frame(tag_win, padx=10, pady=10)
        tag_frame.pack(fill="both", expand=True)
        
        tk.Label(tag_frame, text="添加标签:").pack(anchor="w", pady=(0, 5))
        
        tag_entry = tk.Entry(tag_frame, width=30)
        tag_entry.pack(fill="x", pady=(0, 10))
        tag_entry.focus()
        
        # 常用标签
        self.cursor.execute("SELECT name FROM tags ORDER BY id DESC LIMIT 10")
        common_tags = [row[0] for row in self.cursor.fetchall()]
        
        if common_tags:
            tk.Label(tag_frame, text="常用标签:").pack(anchor="w", pady=(0, 5))
            
            common_frame = tk.Frame(tag_frame)
            common_frame.pack(fill="x", pady=(0, 10))
            
            for tag in common_tags:
                btn = tk.Button(common_frame, text=tag, 
                              command=lambda t=tag: tag_entry.insert(tk.END, t + ","))
                btn.pack(side="left", padx=5)
        
        # 按钮区域
        btn_frame = tk.Frame(tag_frame)
        btn_frame.pack(fill="x", pady=10)
        
        tk.Button(btn_frame, text="添加", 
                 command=lambda: self.save_batch_tags(tag_win, tag_entry.get())).pack(side="right", padx=5)
        tk.Button(btn_frame, text="取消", command=tag_win.destroy).pack(side="right", padx=5)

    def save_batch_tags(self, window, new_tags):
        new_tags = [tag.strip() for tag in new_tags.split(",") if tag.strip()]
        
        if not new_tags:
            messagebox.showwarning("警告", "请输入至少一个标签！")
            return
        
        # 为每个选中的漫画添加标签
        for comic_id in self.selected_comics:
            for tag in new_tags:
                # 检查标签是否已存在
                self.cursor.execute("SELECT id FROM comic_tags WHERE comic_id=? AND tag_name=?", (comic_id, tag))
                if self.cursor.fetchone():
                    continue
                
                # 检查标签是否在标签表中
                self.cursor.execute("SELECT id FROM tags WHERE name=?", (tag,))
                tag_row = self.cursor.fetchone()
                
                if not tag_row:
                    # 插入新标签
                    self.cursor.execute("INSERT INTO tags (name) VALUES (?)", (tag,))
                    tag_id = self.cursor.lastrowid
                else:
                    tag_id = tag_row[0]
                
                # 插入关联
                self.cursor.execute(
                    "INSERT INTO comic_tags (comic_id, tag_id, tag_name) VALUES (?, ?, ?)",
                    (comic_id, tag_id, tag)
                )
        
        self.conn.commit()
        window.destroy()
        
        # 更新详情显示
        if len(self.selected_comics) == 1:
            comic_id = next(iter(self.selected_comics))
            self.select_comic(comic_id)

    def change_cover(self):
        """修改封面图片"""
        if not self.selected_comics:
            messagebox.showwarning("警告", "请先选择一个漫画！")
            return
        
        comic_id = next(iter(self.selected_comics))
        self.cursor.execute("SELECT folder_path FROM comics WHERE id=?", (comic_id,))
        folder_path = self.cursor.fetchone()[0]
        
        # 弹出文件选择对话框
        file_path = filedialog.askopenfilename(
            title="选择封面图片",
            filetypes=[("图片文件", "*.jpg *.jpeg *.png *.gif *.bmp *.webp")]
        )
        
        if not file_path:
            return
        
        # 获取文件扩展名
        _, ext = os.path.splitext(file_path)
        # 新的封面文件名
        new_cover_name = "poster" + ext
        new_cover_path = os.path.join(folder_path, new_cover_name)
        
        # 删除原有的poster文件（所有扩展名）
        poster_pattern = os.path.join(folder_path, "poster.*")
        for old_file in glob.glob(poster_pattern):
            try:
                os.remove(old_file)
            except Exception as e:
                print(f"删除旧封面失败: {e}")
        
        # 复制选中的图片到漫画文件夹
        try:
            shutil.copy2(file_path, new_cover_path)
        except Exception as e:
            messagebox.showerror("错误", f"复制封面图片失败: {e}")
            return
        
        # 更新数据库
        self.cursor.execute("UPDATE comics SET cover_path=? WHERE id=?", (new_cover_path, comic_id))
        self.conn.commit()
        
        # 重新加载漫画列表，以更新封面显示
        self.load_comics()
        messagebox.showinfo("成功", "封面修改成功！")

    def open_folder(self, event):
        """打开漫画文件夹"""
        if not self.selected_comics:
            return
        
        comic_id = next(iter(self.selected_comics))
        self.cursor.execute("SELECT folder_path FROM comics WHERE id=?", (comic_id,))
        folder_path = self.cursor.fetchone()[0]
        
        # 使用系统默认方式打开文件夹
        try:
            os.startfile(folder_path)
        except Exception as e:
            # 如果os.startfile不可用，尝试使用webbrowser
            try:
                webbrowser.open(folder_path)
            except Exception as e2:
                messagebox.showerror("错误", f"无法打开文件夹: {e2}")

if __name__ == "__main__":
    root = tk.Tk()
    app = ComicManager(root)
    root.mainloop()